package org.jeecg.modules.zhima.portal.weixin;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import org.jeecg.modules.zhima.admin.entity.ZmPayOrder;
import org.jeecg.modules.zhima.admin.entity.ZmPlayer;
import org.jeecg.modules.zhima.base.common.Constant.RedisKey;
import org.jeecg.modules.zhima.base.shiro.service.TokenService;
import org.jeecg.modules.zhima.base.util.DateUtils;
import org.jeecg.modules.zhima.base.util.RedisUtil;
import org.jeecg.modules.zhima.center.entity.OmsOrder;
import org.jeecg.modules.zhima.center.entity.UmsMember;
import org.jeecg.modules.zhima.center.enums.OrderStatus;
import org.jeecg.modules.zhima.center.enums.PayStatus;
import org.jeecg.modules.zhima.center.service.IOmsOrderService;
import org.jeecg.modules.zhima.portal.config.WechatAuthProperties;
import org.jeecg.modules.zhima.portal.config.WxPayProperties;
import org.jeecg.modules.zhima.portal.service.IPayOrderService;
import org.jeecg.modules.zhima.portal.service.IPlayerService;
import org.jeecg.modules.zhima.portal.service.IUserService;
import org.jeecg.modules.zhima.portal.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.jeecg.modules.zhima.portal.domain.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author zhigangding
 * @date 2019/12/1
 */
@Slf4j
@Service
public class WechatService {

    /**
     * 服务器第三方session有效时间，单位秒, 默认1天
     */
    private static final Long EXPIRES = 86400L;

    private RestTemplate wxAuthRestTemplate = new RestTemplate();

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private WechatAuthProperties wechatAuthProperties;
    @Autowired
    private WxPayService wxService;
    @Autowired
    private IOmsOrderService orderService;
    @Autowired
    private WxPayProperties config;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IUserService userService;
    @Value("wx.url.token")
    private String WX_TOKEN;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IPlayerService playerService;
    @Autowired
    private IPayOrderService payOrderService;


    public LoginInfo wechatLogin(AuthParam param) {
        LoginInfo loginInfo = new LoginInfo();
        WechatAuthCodeResponse response = getWxSession(param.getCode());

        String wxOpenId = response.getOpenid();
        String wxSessionKey = response.getSession_key();
        UmsMember user = new UmsMember();
        WxUserInfo wxUserInfo;
        if (param.getUserInfo() != null && param.getUserInfo().getUserInfo() != null){
            wxUserInfo = param.getUserInfo().getUserInfo();
            BeanUtils.copyProperties(wxUserInfo, user);
            user.setNickname(wxUserInfo.getNickName());
            user.setAvatar(wxUserInfo.getAvatarUrl());
        }else {
            wxUserInfo = new WxUserInfo();
        }
        user.setWeixinOpenid(wxOpenId);
//        loginInfo.setUserInfo(user);
        wxUserInfo.setWeixinOpenid(wxOpenId);
        wxUserInfo.setSessionKey(wxSessionKey);
//        MemberDetails memberDetails = memberService.loginOrRegisterUser(user, param.getInvitationCode());
        WXMemberDetails memberDetails = userService.loginOrRegisterUser(user, param.getInvitationCode());
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(memberDetails, null, memberDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        UmsMember member = memberDetails.getUmsMember();
        Player player = playerService.getOrAdd(""+member.getId());
        if (!player.getAvatar().equals(param.getUserInfo().getUserInfo().getAvatarUrl())){
            player.setAvatar(param.getUserInfo().getUserInfo().getAvatarUrl());
            playerService.updateById(player);
        }
        loginInfo.setPlayer(player);
        loginInfo.setUserInfo(memberDetails.getUmsMember());
        loginInfo.setToken(tokenService.createTokenByWX(user.getWeixinOpenid(), user.getId(), TokenService.EXPIRATION));
        String loginUserKey = RedisKey.getLoginUserKey(wxOpenId);
        redisUtil.set(loginUserKey, user);
//        loginInfo.setToken(jwtTokenUtil.generateToken(memberDetails));
//        BrandManager brandManager = brandManagerService.getByUserId(user.getId());
//        if (ObjectUtils.allNotNull(brandManager)){
//            loginInfo.setBrandId(brandManager.getBrandId());
//        }
        return loginInfo;
    }

    public WechatAuthCodeResponse getWxSession(String code) {
        log.info(code);
        String urlString = "?appid={appid}&secret={srcret}&js_code={code}&grant_type={grantType}";
        String response = wxAuthRestTemplate.getForObject(
                wechatAuthProperties.getSessionHost() + urlString, String.class,
                wechatAuthProperties.getAppId(),
                wechatAuthProperties.getSecret(),
                code,
                wechatAuthProperties.getGrantType());
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectReader reader = objectMapper.readerFor(WechatAuthCodeResponse.class);
        WechatAuthCodeResponse res;
        try {
            res = reader.readValue(response);
        } catch (IOException e) {
            res = null;
            log.error("反序列化失败", e);
        }
        log.info(response);
        if (null == res) {
            throw new RuntimeException("调用微信接口失败");
        }
        if (res.getErrcode() != null) {
            throw new RuntimeException(res.getErrmsg());
        }
        res.setExpiresIn(res.getExpiresIn() != null ? res.getExpiresIn() : EXPIRES);
        return res;
    }

    public String create3rdSession(String wxOpenId, String wxSessionKey, Long expires) {
        String thirdSessionKey = RandomStringUtils.randomAlphanumeric(64);
        StringBuffer sb = new StringBuffer();
        sb.append(wxSessionKey).append("#").append(wxOpenId);

        stringRedisTemplate.opsForValue().set(thirdSessionKey, sb.toString(), expires, TimeUnit.SECONDS);
        return thirdSessionKey;
    }

    /**
     * 校验并同步支付状态为支付中的订单
     * @param vos
     * @return
     */
    public List<OmsOrder> checkPayStatus(List<OmsOrder> vos){
        if (CollectionUtils.isEmpty(vos)){
            return vos;
        }
        vos.forEach(omsOrder -> {
            if (omsOrder.getStatus().equals(OrderStatus.WAIT_PAY.CODE)){
                try {
                    WxPayOrderQueryResult result = this.query(omsOrder.getOrderSn());
                    if (result.getResultCode().equals(WxPayConstants.ResultCode.SUCCESS)
                            && result.getReturnCode().equals(WxPayConstants.ResultCode.SUCCESS)
                            && result.getTradeState().equals(WxPayConstants.ResultCode.SUCCESS)){
                        omsOrder.setStatus(OrderStatus.WAIT_SEND.CODE);
                        omsOrder.setPayType(2);
                        OmsOrder order = new OmsOrder();
                        BeanUtils.copyProperties(omsOrder, order);
                        orderService.onPaySuccess(order);
                    }
                } catch (WxPayException e) {
                    e.printStackTrace();
                }
            }
        });
        return vos;
    }

    /**
     * 校验并同步支付状态为支付中的订单
     * @param orderSn
     * @return
     */
    public boolean check(String orderSn){
        try {
            WxPayOrderQueryResult result = this.query(orderSn);
            if (result.getResultCode().equals(WxPayConstants.ResultCode.SUCCESS)
                    && result.getReturnCode().equals(WxPayConstants.ResultCode.SUCCESS)
                    && result.getTradeState().equals(WxPayConstants.ResultCode.SUCCESS)){
                return true;
            }
        } catch (WxPayException e) {
            e.printStackTrace();
        }
        return false;
    }

    public OrderPrepayReturn unifiedOrder(String tradeNo, Integer totalFree, String openId) throws WxPayException {

        OrderPrepayReturn prepayReturn = new OrderPrepayReturn();
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setBody("收银台");
        request.setOpenid(openId);
        request.setOutTradeNo(tradeNo);
        request.setSpbillCreateIp("0.0.0.0");
        String time = DateUtils.date2Str(DateUtils.yyyymmddhhmmss.get());
        request.setTimeStart(time);
        String timeExpire = DateUtils.getDateStr(new Date(), Calendar.DATE, 1, DateUtils.yyyymmddhhmmss.get());
        request.setTimeExpire(timeExpire);
        request.setTotalFee(totalFree);
        request.setNotifyUrl(config.getNotifyUrl());
        request.setAttach("1");
        WxPayUnifiedOrderResult result = wxService.unifiedOrder(request);
        if (result.getResultCode().equals(WxPayConstants.ResultCode.SUCCESS)){
            String timeStamp = ""+(System.currentTimeMillis()/1000);
            prepayReturn.setPackageName("prepay_id="+result.getPrepayId());
            prepayReturn.setSignType(WXPayConstants.SignType.MD5.name());
            Map<String, String> packageParams = new HashMap<>();
            packageParams.put("appId", config.getAppId());
            packageParams.put("nonceStr",result.getNonceStr());
            packageParams.put("timeStamp",timeStamp);
            packageParams.put("signType", prepayReturn.getSignType());
            packageParams.put("package", prepayReturn.getPackageName());
            String sign="";
            try {
                sign= WXPayUtil.generateSignature(packageParams, config.getMchKey());
            } catch (Exception e) {
                e.printStackTrace();
            }
            prepayReturn.setPaySign(sign);
            prepayReturn.setNonceStr(result.getNonceStr());
            prepayReturn.setTimeStamp(timeStamp);
        }
        return prepayReturn;
    }

    /**
     * 查询微信支付订单
     * @param orderSn
     * @return
     * @throws WxPayException
     */
    public WxPayOrderQueryResult query(String orderSn) throws WxPayException {
        WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
        request.setOutTradeNo(orderSn);
        WxPayOrderQueryResult result = wxService.queryOrder(request);
        return result;
    }

    public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlResult) throws WxPayException {
        return wxService.parseOrderNotifyResult(xmlResult);
    }

    public static void main(String[] args) {
        System.out.println(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
    }

}
